home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / pc / BEERSRC.ZIP / FILEMAN.C < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-27  |  13.4 KB  |  543 lines

  1.  
  2. /*-------------------------------------------------------*/
  3. /*                                                       */
  4. /*               F I L E M A N A G E R                   */
  5. /*           [c] copyright 1993 by Alpha-Helix           */
  6. /*               written by Dany Schoch                  */
  7. /*                                                       */
  8. /*   Revision List:                                      */
  9. /*    27. May 93: Memory peak meter added.          */
  10. /*      28.       : >64kB file load error corrected.     */
  11. /*    30. June  : 'shutfilemanager' crash corrected.   */
  12. /*    22. Sept  : 'openfile' added.             */
  13. /*    30. Nov      : 'errno.h' error compatibility added. */
  14. /*      19. Dez   : 'printbuffer' added.                 */
  15.  
  16.  
  17.  
  18. #include <alloc.h>
  19. #include <string.h>
  20. #include <stdlib.h>
  21. #include <dos.h>
  22. #include <io.h>
  23. #include <fcntl.h>
  24. #include <stdio.h>
  25. #include <dir.h>
  26. #include <errno.h>
  27.  
  28. #include "xms.h"
  29. #include "fileman.h"
  30.  
  31.  
  32. #define TRUE        1
  33. #define FALSE        0
  34.  
  35. typedef unsigned long ulong;
  36. typedef unsigned int uint;
  37.  
  38. #ifdef DEBUG
  39. ulong   mindosmem = 0xffffffff;
  40. void far *mem_farmalloc(ulong size)
  41. {
  42.    void far *ptr;
  43.  
  44.    ptr = farmalloc(size);
  45.    if (mindosmem > farcoreleft()) mindosmem = farcoreleft();
  46.  
  47.    return ptr;
  48. }
  49. #define farmalloc(x)        mem_farmalloc(x)
  50. #endif
  51.  
  52.  
  53. #define HDRSIZE            30
  54.  
  55. struct filestrc {
  56.    char  name[14];        // Name of file.
  57.    ulong size;            // It's size.
  58.    int   flags;            // Buffering flags.
  59.    long  fptr;            // File pointer to access it's data.
  60. };
  61.  
  62. struct dbasestrc {
  63.    char   basename[MAXPATH];    // Path and name of the open data base.
  64.    int    filvar;        // File handle of data base.
  65.    int    nfiles;        // # of files in data base.
  66.    struct filestrc file[];
  67. };
  68.  
  69.  
  70. struct entrystrc {
  71.    char   name[14];        // Name of the buffered file.
  72.    ulong  size;
  73.    ulong  addr;            // 32 bit offset into XMS or far pointer.
  74.    int    hits;            // Cache hit counter.
  75.    int    flags;
  76. };
  77.  
  78. static int    XMShandle;    // Handle of allocated extended memory.
  79. static ulong  xmspointer;    // Pointer to free XMS.
  80. static ulong  freexms;        // Free xtended mem.
  81. static int    nentries;        // # of table entries.
  82. static struct entrystrc *entry; // Entry table.
  83. static void   (*error)(char *text, int code, ...);
  84.  
  85.  
  86. #pragma argsused
  87. static void errf(char *text, int code, ...)
  88. {
  89.    return;
  90. }
  91.  
  92. /*------------------------------------------------------
  93. Function: initfilemanager
  94.  
  95. Description: Initializes the Alpha-Helix file manager.
  96.     handles: max # of files that can be buffered.
  97.     minsize:\ extended memory that will be allocated
  98.     maxsize:/ (in kB)
  99.     err    : Pointer to alternative error handler.
  100. Returns: kBytes allocated on success.
  101.           0 not enough free XMS memory.
  102.          -1 not enough main memory.
  103. ------------------------------------------------------*/
  104. int initfilemanager(int handles,
  105.             int minsize, int maxsize,
  106.             void (*err)(char *text, int code, ...))
  107. {
  108.  
  109. // Install custom error handler.
  110.    if (err == NULL) error = errf; else error = err;
  111.  
  112.    entry = NULL;
  113.    XMShandle = -1;
  114.  
  115. // Check if XMS driver is installed.
  116.    if (!initXMS()) return 0;    // Just no XMS available.
  117.  
  118. // Enough free memory available ?
  119.    freexms = getfreeXMS();
  120.    if (freexms < minsize) return 0;
  121.  
  122.    if (freexms > maxsize)
  123.       XMShandle = allocXMS(freexms = maxsize);
  124.    else
  125.       XMShandle = allocXMS(freexms);
  126.  
  127.    if (XMShandle == -1) return 0;
  128.    freexms *= 1024;        // We want it in bytes not Kbs.
  129.    xmspointer = 0;        // First the whole XMS id free.
  130.  
  131. // Allocate memory for the buffer table.
  132.    nentries = handles;
  133.    entry = (struct entrystrc *)calloc(nentries, sizeof(struct entrystrc));
  134.    if (entry == NULL) {
  135.       freeXMS(XMShandle);
  136.       return -1;                // Fatal error.
  137.    }
  138.  
  139.    return (freexms / 1024);    // Successful
  140.  
  141. }
  142.  
  143.  
  144. /*------------------------------------------------------
  145. Function: shutfilemanager
  146.  
  147. Description: Leaves the filemanager and frees the allocated
  148.          memory.
  149.          NOTE: memory allocated by 'opendatabase'
  150.            won't be freed.
  151. ------------------------------------------------------*/
  152. void shutfilemanager(void)
  153. {
  154.    if (entry != NULL) free(entry);
  155.    if (XMShandle != -1) freeXMS(XMShandle);
  156.    shutXMS();
  157. #ifdef DEBUG
  158.    printf("\nDOS free memory: %ld bytes.\n", mindosmem);
  159. #endif
  160. }
  161.  
  162. #ifdef DEBUG
  163. void printbuffer(void)
  164. {
  165.    int   i;
  166.  
  167.    printf("Name           Size      Addr     Hits\n");
  168.    printf("--------------------------------------\n");
  169.    for (i = 0; i < nentries; i++) {
  170.       if (entry[i].size != 0)
  171.      printf("%s       %ld        %lx      %d\n",
  172.         entry[i].name, entry[i].size, entry[i].addr, entry[i].hits);
  173.    }
  174.  
  175. }
  176. #endif
  177.  
  178. // -- Start of private area.
  179.  
  180. static struct entrystrc *findfreeentry(void)
  181. {
  182.    int   i;
  183.  
  184.    for (i = 0; i < nentries; i++) {
  185.       if (entry[i].size == 0) break;
  186.    }
  187.    if (entry[i].size == 0) return &entry[i]; else return NULL;
  188.  
  189. }
  190.  
  191.  
  192. static struct entrystrc *findentry(char *file)
  193. {
  194.    int    i;
  195.    struct entrystrc *result;
  196.  
  197.    result = NULL;
  198.    if (entry != NULL) {
  199.       for (i = 0; i < nentries; i++) {
  200.      if (strcmpi(file, entry[i].name) == 0) {
  201.         result = &entry[i];
  202.         break;
  203.      }
  204.       }
  205.    }
  206.    return result;
  207.  
  208. }
  209.  
  210.  
  211. static void freeentry(int i)
  212. {
  213.    ulong  size;
  214.    struct entrystrc *result;
  215.  
  216. // Move memory blocks.
  217.    result = &entry[i];
  218.    size = result->size;
  219.    moveXMS(XMShandle, result->addr+size,
  220.        XMShandle, result->addr, xmspointer-result->addr-result->size);
  221.    freexms += size;
  222.    xmspointer -= size;            // Adjust free xms pointer.
  223.  
  224. // Move index table.
  225.    if (i < nentries-1) {
  226.       memmove(result, result+1, (nentries-i-1)*sizeof(struct entrystrc));
  227.    }
  228.    for ( ; i < nentries-1; i++) entry[i].addr -= size;
  229.    entry[nentries-1].size = 0;        // Mark free slot.
  230.  
  231. }
  232.  
  233. static int lightxms(void)
  234. {
  235.    int    count;
  236.    int    i;
  237.    struct entrystrc *result;
  238.  
  239.    count = 0;
  240.    do {
  241.  
  242. // Look for a block to remove.
  243.       result = NULL;
  244.       for (i = 0; i < nentries; i++) {
  245.      if ((entry[i].hits == count) && (entry[i].size != 0)) {
  246.         result = &entry[i];
  247.         break;
  248.      }
  249.       }
  250.       if (result) {
  251.      freeentry(i);
  252. // Decrement hitcounts.
  253.      for (i = 0; i < nentries; i++)
  254.         if (entry[i].hits > 0) entry[i].hits--;
  255.  
  256.      return TRUE;
  257.       }
  258.    } while (count++ < 20);
  259.  
  260.    return FALSE;
  261. }
  262.  
  263.  
  264. static void buffer(char *file, void far *data, ulong size, int flags)
  265. {
  266.    struct entrystrc *result;
  267.  
  268.  
  269.    strupr(file);
  270.    if ((flags & M_XMS) && (XMShandle != -1)) {
  271.    // Buffer in extended memory.
  272.       if (!(flags & M_NOFREEUP)) {
  273.      while (freexms < size)
  274.         if (!lightxms()) break;    // Try to make space.
  275.       }
  276.       result = findfreeentry();
  277.       if ((result != NULL) && (freexms >= size)) {
  278.      strcpy(result->name, file);
  279.      result->size = size;
  280.      result->addr = xmspointer;
  281.      result->hits = 0;
  282.      result->flags = flags;
  283.      moveXMS(0, (ulong)data, XMShandle, result->addr, size);
  284.      freexms -= size;
  285.      xmspointer += size;        // Move pointer to remaining free XMS.
  286.       }
  287.    }
  288.  
  289. }
  290.  
  291. // --- End of private area.
  292.  
  293.  
  294.  
  295.  
  296. /*------------------------------------------------------
  297. Function: opendatabase
  298.  
  299. Description: Opens a special type of file: The Alpha-Helix
  300.          James Bond Baller game data library file
  301.          type.
  302. ------------------------------------------------------*/
  303. void *opendatabase(char *file)
  304. {
  305.    int    filvar;
  306.    int    nfiles;
  307.    uint   nread;
  308.    struct dbasestrc *ptr;
  309.    char   hdr[HDRSIZE];
  310.    int    mode;
  311.  
  312.    if (_dos_open(file, O_RDONLY, &filvar)) {
  313.       (*error)("opendatabase", ENOFILE, file);
  314.       return NULL;
  315.    }
  316.  
  317.    _dos_read(filvar, hdr, HDRSIZE, &nread);
  318.    _dos_read(filvar, &mode, sizeof(int), &nread);
  319.    _dos_read(filvar, &nfiles, sizeof(int), &nread);
  320.    ptr = malloc(sizeof(struct dbasestrc) + nfiles*sizeof(struct filestrc));
  321.    if (ptr == NULL) {
  322.       _dos_close(filvar);
  323.       (*error)("opendatabase", ENOMEM);
  324.       return NULL;
  325.    }
  326.  
  327. // Fill in the newly created structure.
  328.    strcpy(ptr->basename, file);
  329.    ptr->filvar = filvar;
  330.    ptr->nfiles = nfiles;
  331.    _dos_read(filvar, (void far *)ptr->file,
  332.          nfiles*sizeof(struct filestrc), &nread);
  333.  
  334.    return (void *)ptr;
  335.  
  336. }
  337.  
  338. /*------------------------------------------------------
  339. Function: closedatabase
  340.  
  341. Description: Undoes the effect of a previous 'opendatabase'.
  342. ------------------------------------------------------*/
  343. void closedatabase(void *database)
  344. {
  345.    struct dbasestrc *ptr;
  346.  
  347.    ptr = (struct dbasestrc *)database;
  348.    _dos_close(ptr->filvar);
  349.    free(ptr);
  350. }
  351.  
  352.  
  353. /*------------------------------------------------------
  354. Function: loadfile
  355.  
  356. Description: Reserves enough memory to hold the file
  357.          in memory and loads it from the database.
  358. ------------------------------------------------------*/
  359. void far *loadfile(void *database, char *file)
  360. {
  361.    struct entrystrc *result;
  362.    struct dbasestrc *ptr;
  363.    void   far *data;
  364.    char   huge *p;
  365.    ulong  fsize, msize;        // file and memory size of file respectively.
  366.    int    i, j;
  367.    uint   nread;
  368.  
  369.    ptr = (struct dbasestrc *)database;
  370.    result = findentry(file);
  371.    if (result != NULL) {
  372.       // File is in buffer.
  373.       if (result->hits < 20) result->hits++;
  374.       // Allocated memory and copy block.
  375.       if ((data = farmalloc(result->size)) == NULL) {
  376.      (*error)("loadfile", ENOMEM);
  377.      return NULL;
  378.       }
  379.       moveXMS(XMShandle, result->addr, 0, (ulong)data, result->size);
  380.    } else {
  381.       // File must be read from disk.
  382.       for (i = 0, j = -1; i < ptr->nfiles; i++) {
  383.      if (strcmpi(file, ptr->file[i].name) == 0) {
  384.         j = i;
  385.         break;
  386.      }
  387.       }
  388.       if (j == -1) {
  389.      (*error)("loadfile", ENOFILE, file);
  390.      return NULL;
  391.       }
  392.       lseek(ptr->filvar, ptr->file[j].fptr, SEEK_SET);
  393.       fsize = ptr->file[j].size;
  394.       msize = (fsize + 1) & 0xfffffffel;    // make it even.
  395.       if ((data = farmalloc(msize)) == NULL) {
  396.      (*error)("loadfile", ENOMEM);
  397.      return NULL;
  398.       }
  399.       p = data;
  400.       while (fsize > 65000) {
  401.      _dos_read(ptr->filvar, p, 65000, &nread);
  402.      fsize -= 65000; p += 65000;
  403.       }
  404.       _dos_read(ptr->filvar, p, fsize, &nread);
  405.  
  406.       buffer(file, data, ptr->file[j].size, ptr->file[j].flags);
  407.    }
  408.  
  409.    return data;
  410.  
  411. }
  412.  
  413.  
  414. /*------------------------------------------------------
  415. Function: loadfiledirect
  416.  
  417. Description: Allocates memory for the file and loads
  418.          it if present from the buffer, otherwise
  419.          from disk.
  420. ------------------------------------------------------*/
  421. void far *loadfiledirect(char *file, int flags)
  422. {
  423.    int    filvar;
  424.    struct entrystrc *result;
  425.    void   far *ptr;
  426.    char   huge *p;
  427.    ulong  fsize, msize;        // real size and size in memory of file.
  428.    uint   nread;
  429.  
  430.    result = findentry(file);
  431.    if (result != NULL) {
  432.       // File is in buffer.
  433.       if (result->hits < 20) result->hits++;
  434.       // Allocated memory and copy block.
  435.       if ((ptr = farmalloc(result->size)) == NULL) {
  436.      (*error)("loadfiledirect", ENOMEM);
  437.      return NULL;
  438.       }
  439.       moveXMS(XMShandle, result->addr, 0, (ulong)ptr, result->size);
  440.    } else {
  441.       // File must be read from disk.
  442.       if (_dos_open(file, O_RDONLY, &filvar)) {
  443.      (*error)("loadfiledirect", ENOFILE, file);
  444.      return NULL;
  445.       }
  446.       fsize = filelength(filvar);
  447.       msize = (fsize + 1) & 0xfffffffel;    // round it up.
  448.       if ((ptr = farmalloc(msize)) == NULL) {
  449.      _dos_close(filvar);
  450.      (*error)("loadfiledirect", ENOMEM);
  451.      return NULL;
  452.       }
  453.       p = ptr;
  454.       while (fsize > 65000) {
  455.      _dos_read(filvar, p, 65000, &nread);
  456.      fsize -= 65000; p += 65000;
  457.       }
  458.       _dos_read(filvar, p, fsize, &nread);
  459.       _dos_close(filvar);
  460.  
  461.       buffer(file, ptr, msize, flags);
  462.    }
  463.  
  464.    return ptr;
  465.  
  466. }
  467.  
  468.  
  469. void unloadfile(void far *ptr)
  470. {
  471.    farfree(ptr);
  472. }
  473.  
  474.  
  475. /*------------------------------------------------------
  476. Function: openfile
  477.  
  478. Description: Same as loadfile, but doesn't read it into
  479.          memory. Just sets the file pointer to
  480.          the start of the file.
  481. Returns: File handle for further access.
  482. ------------------------------------------------------*/
  483. int openfile(void *database, char *file)
  484. {
  485.    struct dbasestrc *ptr;        // Pointer to data base directory.
  486.    int    i, j;
  487.    int    filvar;
  488.  
  489.  
  490.    ptr = (struct dbasestrc *)database;
  491.    for (i = 0, j = -1; i < ptr->nfiles; i++) {
  492.       if (strcmpi(file, ptr->file[i].name) == 0) {
  493.      j = i;
  494.      break;
  495.       }
  496.    }
  497.    if (j == -1) {
  498.       (*error)("openfile", ENOFILE, file);
  499.       return -1;
  500.    }
  501.  
  502. // Re-open database to get a free file pointer.
  503.    if (_dos_open(ptr->basename, O_RDONLY, &filvar) != 0) {
  504.       (*error)("openfile", ENOFILE, ptr->basename);
  505.       return -1;
  506.    }
  507. // Seek to data.
  508.    lseek(filvar, ptr->file[j].fptr, SEEK_SET);
  509.  
  510.    return filvar;
  511. }
  512.  
  513.  
  514. /*------------------------------------------------------
  515. Function: openfiledirect
  516.  
  517. Description: In fact this is the same as open the file
  518.          for read only using _dos_open.
  519. ------------------------------------------------------*/
  520. int openfiledirect(char *file)
  521. {
  522.    int   filvar;
  523.  
  524.    if (_dos_open(file, O_RDONLY, &filvar) != 0) {
  525.       (*error)("openfiledirect", ENOFILE, file);
  526.       return -1;
  527.    }
  528.  
  529.    return filvar;
  530. }
  531.  
  532.  
  533. /*------------------------------------------------------
  534. Function: closefile
  535.  
  536. Description:
  537. ------------------------------------------------------*/
  538. void closefile(int filvar)
  539. {
  540.    _dos_close(filvar);
  541. }
  542.  
  543.